/*
 * @Author: WangShuai 1830773767@qq.com
 * @Date: 2025-05-06 11:16:35
 * @LastEditors: WangShuai 1830773767@qq.com
 * @LastEditTime: 2025-05-10 23:55:35
 * @FilePath: \Webgl-basic\lib\index.js
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
/**
 * 初始化着色器, 创建并配置程序对象, 返回
 * @param {WebGLRenderingContext} gl : webgl上下文对象
 * @param {string} vshader_source : 顶点着色器源码
 * @param {string} fshader_source : 片元着色器源码
 * @returns: program程序对象
 */
export function initShader(gl, vshader_source, fshader_source) {
    // 创建着色器
    const vertexShader = createShaderFromString(gl, gl.VERTEX_SHADER, vshader_source)
    const fragmentShader = createShaderFromString(gl, gl.FRAGMENT_SHADER, fshader_source)

    // 创建一个程序对象 操作手，专门负责javaScript和shader着色器的通讯
    const program = gl.createProgram()
    gl.attachShader(program, vertexShader)
    gl.attachShader(program, fragmentShader)

    // 将javascrpt和程序对象关联
    gl.linkProgram(program)

    // 使用程序对象
    gl.useProgram(program)

    // 返回程序对象
    return program
}

function createShaderFromString(gl, type, str) {
    return createShader(gl, type, str);
}

function createShader(gl, type, source) {
    let shader = gl.createShader(type);
    gl.shaderSource(shader, source);
    gl.compileShader(shader);
    //检测是否编译正常。
    let success = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
    if (success) {
        return shader;
    }
    console.error(gl.getShaderInfoLog(shader));
    gl.deleteShader(shader);
}


//使用缓冲区绘制三角形
export const createBufferTriangle = (gl, points, targetName) => {
    createBuffer(gl, points, targetName)
    const n = points.length / 2;
    return n
}
export const createCubeGem = (gl, indices, config = {}, params) => {
    // console.log(config.entries());
    for (const [key, value] of config.entries()) {
        createBuffer(gl, value, key, params);
    }
    //创建索引缓冲区
    let indexBuffer = gl.createBuffer();
    //创建绑定索引缓冲区
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
    //开启隐藏面剔除
    gl.enable(gl.DEPTH_TEST)
    //清除深度缓冲区
    gl.clear(gl.DEPTH_BUFFER_BIT)
    return indices.length;
}

//创建但缓冲区
export const createBuffer = (gl, dataSource, attributeName, params) => {
    const vertexPointer = {
        size: 2,
        type: gl.FLOAT,
        normalize: false,
        stripe: 0,
        offset: 0,
    }
    const FSIZE = 4;

    const resParam = Object.assign(vertexPointer, params);
    const {
        size,
        type,
        normalize,
        offset
    } = resParam
    const stripe = FSIZE * size;
    const target = gl.getAttribLocation(gl.program, attributeName);
    //创建缓冲区
    const buffer = gl.createBuffer();
    //数据转32为位
    dataSource = new Float32Array(dataSource)
    //给定缓冲区的用途
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
    //向ARRY_BUFFER中写入数据
    gl.bufferData(gl.ARRAY_BUFFER, dataSource, gl.STATIC_DRAW)
    gl.vertexAttribPointer(target, size, type, normalize, stripe, offset)
    gl.enableVertexAttribArray(target)
    return dataSource.length / size
}

//给定矩形中心点,以及宽高,是生成geomrtry
//creatRectGeom构造坐标,并且将坐标放入缓冲区中
export const creatRectGeom = (gl, center, width, height) => {
    const centerX = center[0];
    const centerY = center[1];
    let points = [
        centerX - width / 2, centerY + height / 2,
        centerX - width / 2, centerY - height / 2,
        centerX + width / 2, centerY + height / 2,
        centerX + width / 2, centerY - height / 2,
    ]
    points = new Float32Array(points);
    createBuffer(gl, points, 'a_Position');
    return points.length / 2
}
export function loadTexture(gl, src, attribute, callback) {
    let img = new Image();
    img.crossOrigin = "anonymous";
    img.onload = function () {
        // 1.激活0号纹理通道，默认激活0号纹理通道
        gl.activeTexture(gl.TEXTURE0);
        // 创建纹理
        const texture = gl.createTexture();
        // 向target绑定纹理对象
        gl.bindTexture(gl.TEXTURE_2D, texture);
        // 配置纹理参数
        gl.texParameterf(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
        gl.texParameterf(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
        // 配置纹理图像
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);
        // 将0号纹理传递给着色器
        gl.uniform1i(attribute, 0);
        callback && callback();

    }
    img.src = src;
}

//绘制立方体函数
export const createCube = (gl, center, width, long, height) => {
    let a_Position = gl.getAttribLocation(gl.program, 'a_Position');
    let a_Color = gl.getAttribLocation(gl.program, 'a_Color');
    let a_Normal = gl.getAttribLocation(gl.program, 'a_Normal');
    const centerX = center[0]
    const centerY = center[1]
    const centerZ = center[2]
    const v0 = [centerX + width / 2, centerY + long / 2, centerZ + height / 2]
    const v1 = [centerX - width / 2, centerY + long / 2, centerZ + height / 2]
    const v2 = [centerX - width / 2, centerY - long / 2, centerZ + height / 2]
    const v3 = [centerX + width / 2, centerY - long / 2, centerZ + height / 2]
    const v4 = [centerX + width / 2, centerY - long / 2, centerZ - height / 2]
    const v5 = [centerX + width / 2, centerY + long / 2, centerZ - height / 2]
    const v6 = [centerX - width / 2, centerY + long / 2, centerZ - height / 2]
    const v7 = [centerX - width / 2, centerY - long / 2, centerZ - height / 2]
    const vertices = new Float32Array([ // Vertex coordinates
        ...v0, ...v1, ...v2, ...v3, // v0-v1-v2-v3 front
        ...v0, ...v3, ...v4, ...v5, // v0-v3-v4-v5 right
        ...v0, ...v5, ...v6, ...v1, // v0-v5-v6-v1 up
        ...v1, ...v6, ...v7, ...v2, // v1-v6-v7-v2 left
        ...v7, ...v4, ...v3, ...v2, // v7-v4-v3-v2 down
        ...v4, ...v7, ...v6, ...v5 // v4-v7-v6-v5 back
    ]);
    // console.log(vertices);
    const colors = new Float32Array([ // Colors
        0.4, 0.4, 1.0, 0.4, 0.4, 1.0, 0.4, 0.4, 1.0, 0.4, 0.4, 1.0, // v0-v1-v2-v3 front(blue)
        0.4, 1.0, 0.4, 0.4, 1.0, 0.4, 0.4, 1.0, 0.4, 0.4, 1.0, 0.4, // v0-v3-v4-v5 right(green)
        1.0, 0.4, 0.4, 1.0, 0.4, 0.4, 1.0, 0.4, 0.4, 1.0, 0.4, 0.4, // v0-v5-v6-v1 up(red)
        1.0, 1.0, 0.4, 1.0, 1.0, 0.4, 1.0, 1.0, 0.4, 1.0, 1.0, 0.4, // v1-v6-v7-v2 left
        1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, // v7-v4-v3-v2 down
        0.4, 1.0, 1.0, 0.4, 1.0, 1.0, 0.4, 1.0, 1.0, 0.4, 1.0, 1.0 // v4-v7-v6-v5 back
    ]);
    const indices = new Uint8Array([ // Indices of the vertices
        0, 1, 2, 0, 2, 3, // front
        4, 5, 6, 4, 6, 7, // right
        8, 9, 10, 8, 10, 11, // up
        12, 13, 14, 12, 14, 15, // left
        16, 17, 18, 16, 18, 19, // down
        20, 21, 22, 20, 22, 23 // back
    ]);
    // 顶点法向量
    let normals = new Float32Array([
        ...[0, 0, 1], ...[0, 0, 1], ...[0, 0, 1], ...[0, 0, 1], //前平面
        ...[1, 0, 0], ...[1, 0, 0], ...[1, 0, 0], ...[1, 0, 0], //右平面
        ...[0, 1, 0], ...[0, 1, 0], ...[0, 1, 0], ...[0, 1, 0], //上平面
        ...[-1, 0, 0], ...[-1, 0, 0], ...[-1, 0, 0], ...[-1, 0, 0], //左平面
        ...[0, -1, 0], ...[0, -1, 0], ...[0, -1, 0], ...[0, -1, 0], //下平面
        ...[0, 0, -1], ...[0, 0, -1], ...[0, 0, -1], ...[0, 0, -1], //后平面
    ]);
    // 创建坐标顶点缓冲区
    let buffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
    gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
    gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, 0, 0);
    gl.enableVertexAttribArray(a_Position);
    // 创建颜色缓冲区
    let bufferColor = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, bufferColor);
    gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
    gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, 0, 0);
    gl.enableVertexAttribArray(a_Color);

    // 创建法向量缓冲区
    let bufferNormal = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, bufferNormal);
    gl.bufferData(gl.ARRAY_BUFFER, normals, gl.STATIC_DRAW);
    gl.vertexAttribPointer(a_Normal, 3, gl.FLOAT, false, 0, 0);
    gl.enableVertexAttribArray(a_Normal);
    // 创建索引缓冲区
    let indexBuffer = gl.createBuffer();
    // 绑定索引缓冲区
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
    // 开启隐藏面消除
    gl.enable(gl.DEPTH_TEST)
    // 清空深度缓冲区
    gl.clear(gl.DEPTH_BUFFER_BIT)
    return indices.length
}